using System;
using System.Collections.Generic;
using System.IO;
using System.Text;

using Microsoft.Build.Framework;
using Microsoft.Build.Utilities;
using Microsoft.Win32;

namespace cosoware.MSBuildTasks.Subversion
{
    /// <summary>
    /// Base class for subversion tool based tasks.
    /// </summary>
    public abstract class SvnTask : ToolTask
    {
        /// <summary>
        /// Command line switches.
        /// </summary>
        private CommandLineBuilder _switches;

        /// <summary>
        /// Output task items.
        /// </summary>
        private readonly Dictionary<string, ITaskItem> _inputItems = new Dictionary<string,ITaskItem>();

        /// <summary>
        /// Output task items.
        /// </summary>
        private readonly Dictionary<string,ITaskItem> _outputItems = new Dictionary<string, ITaskItem>();

        /// <summary>
        /// Initializes a new instance of the <see cref="SvnTask"/> class.
        /// </summary>
        public SvnTask()
        {
        }

        /// <summary>
        /// Determines where execution errors raised by the executable file should be handled.
        /// </summary>
        /// <returns>
        /// true if the method runs successfully; otherwise, false.
        /// </returns>
        protected override bool HandleTaskExecutionErrors()
        {
            return false;
        }

        /// <summary>
        /// Gets the name of the executable file to run.
        /// </summary>
        /// <returns>
        /// The name of the executable file to run.
        /// </returns>
        protected override string GenerateFullPathToTool()
        {
            return ToolName;
        }

        /// <summary>
        /// Gets the name of the executable file to run.
        /// </summary>
        /// <value></value>
        /// <returns>The name of the executable file to run.</returns>
        protected override string ToolName
        {
            get { return "svn.exe"; }
        }

        /// <summary>
        /// Returns a string value containing the command line arguments to pass directly to the executable file.
        /// </summary>
        /// <returns>
        /// A string value containing the command line arguments to pass directly to the executable file.
        /// </returns>
        protected override sealed string GenerateCommandLineCommands()
        {
            _switches = new CommandLineBuilder();
            AppendSwitch(Command);
            BuildCommandLine();
            return _switches.ToString();
        }

        /// <summary>
        /// Gets the command.
        /// </summary>
        /// <value>The command.</value>
        protected abstract string Command { get; }

        /// <summary>
        /// When overriden builds the parameters command line.
        /// </summary>
        protected abstract void BuildCommandLine();

        /// <summary>
        /// Appends the parameter to command line.
        /// </summary>
        /// <param name="key">The key.</param>
        protected void AppendSwitch(string key)
        {
            _switches.AppendSwitch(key);
        }

        /// <summary>
        /// Appends the parameter to command line.
        /// </summary>
        /// <param name="value">The value.</param>
        protected void AppendSwitch(ITaskItem value)
        {
            _switches.AppendSwitchIfNotNull("", value);
        }

        /// <summary>
        /// Appends the parameter to command line.
        /// </summary>
        /// <param name="key">The key.</param>
        /// <param name="value">The value.</param>
        protected void AppendSwitch(string key, ITaskItem value)
        {
            _switches.AppendSwitchIfNotNull(key + " ", value);
        }

        /// <summary>
        /// Runs the exectuable file with the specified task parameters.
        /// Initializes output parameters from output.
        /// </summary>
        /// <returns>
        /// true if the task runs successfully; otherwise, false.
        /// </returns>
        public override bool Execute()
        {
            if (!BeforeExecute())
            {
                Log.LogError("Preprocessing of Subversion {0} command execution failed.", Command);
                return false;
            }
            if (!base.Execute())
            {
                Log.LogError("Subversion {0} command execution failed.", Command);
                return false;
            }
            if (!AfterExecute())
            {
                Log.LogError("Postprocessing of Subversion {0} command execution failed.", Command);
                return false;
            }
            return true;
        }

        /// <summary>
        /// Runs befores the execute.
        /// </summary>
        /// <returns></returns>
        protected virtual bool BeforeExecute()
        {
            return true;
        }

        /// <summary>
        /// Runs after execute.
        /// </summary>
        protected virtual bool AfterExecute()
        {
            if (ExitCode != 0)
            {
                Log.LogError("Task completed with error. Subversion exit code: {0}", ExitCode);
                return false;
            }
            else
            {
                Log.LogMessage(MessageImportance.High, "Task completed. Subversion exit code: {0}", ExitCode);
                return true;
            }
        }

        /// <summary>
        /// Registers the output task item.
        /// </summary>
        /// <param name="key">The key.</param>
        /// <param name="item">The item.</param>
        protected void InitializeInputTaskItem(string key, ITaskItem item)
        {
            _inputItems[key] = item;
        }

        /// <summary>
        /// Gets the input task item.
        /// </summary>
        /// <param name="key">The key.</param>
        /// <returns></returns>
        protected ITaskItem GetInputTaskItem(string key)
        {
            if (!_inputItems.ContainsKey(key))
            {
                _inputItems[key] = new TaskItem();;
            }
            return _inputItems[key];
        }

        /// <summary>
        /// Registers the output task item.
        /// </summary>
        /// <param name="key">The key.</param>
        /// <param name="item">The item.</param>
        protected void RegisterOutputTaskItem(string key, ITaskItem item)
        {
            _outputItems[key] = item;
        }

        /// <summary>
        /// Gets the output task item.
        /// </summary>
        /// <param name="key">The key.</param>
        /// <returns></returns>
        protected ITaskItem GetOutputTaskItem(string key)
        {
            if(!_outputItems.ContainsKey(key))
            {
                _outputItems[key] = new TaskItem();;
            }
            return _outputItems[key];
        }
    }
}
